package com.vcc.service.impl;


import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.model.AmountData;
import com.vcc.core.model.CountData;
import com.vcc.core.model.RateData;
import com.vcc.core.util.DateUtil;
import com.vcc.core.util.JsonUtil;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.Role;
import com.vcc.data.entity.Transaction;
import com.vcc.data.entity.UserCard;
import com.vcc.data.mapper.TransactionMapper;
import com.vcc.service.client.vo.statistics.UserTransactionVo;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.TransactionService;
import com.vcc.service.service.UserCardService;
import com.vcc.service.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.vcc.data.entity.table.BossUserTableDef.BOSS_USER;
import static com.vcc.data.entity.table.TransactionTableDef.TRANSACTION;
import static com.vcc.data.entity.table.UserTableDef.USER;


@Service
public class TransactionServiceImpl extends ServiceImpl<TransactionMapper, Transaction> implements TransactionService {

    @Resource
    private UserService userService;
    @Resource
    private UserCardService userCardService;

    @Override
    public Boolean existsByTranId(String tranId) {
        return queryChain().eq(Transaction::getTranId, tranId).exists();
    }

    @Override
    public Boolean existsByChannelTranId(String channelTranId) {
        return queryChain().eq(Transaction::getChannelTranId, channelTranId).exists();
    }

    @Override
    public String getTranIdByChannelTranId(String channelTranId) {
        return mapper.getTranIdByChannelTranId(channelTranId);
    }

    @Override
    public Transaction getByChannelTranId(String channelTranId) {
        return queryChain().eq(Transaction::getChannelTranId, channelTranId).oneOpt().orElse(null);
    }

    @Override
    public Boolean updateStatusById(Long id, String status) {
        return updateChain()
                .set(Transaction::getStatus, status)
                .eq(Transaction::getId, id)
                .update();
    }

    @Override
    public Boolean updateStatusByChannelTranId(String channelTranId, String status) {
        return updateChain()
                .set(Transaction::getStatus, status)
                .eq(Transaction::getChannelTranId, channelTranId)
                .update();
    }

    @Override
    public Boolean updateReversalTran(
            String channelTranId,
            String status,
            BigDecimal settleAmount,
            String settleCurrency,
            Date settleDate,
            Date postDate,
            Boolean hasClear
    ) {
        return updateChain()
                .set(Transaction::getStatus, status)
                .set(Transaction::getSettleAmount, settleAmount)
                .set(Transaction::getSettleCurrency, settleCurrency)
                .set(Transaction::getBillingAmount, settleAmount)
                .set(Transaction::getBillingCurrency, settleCurrency)
                .set(Transaction::getSettleDate, settleDate)
                .set(Transaction::getPostDate, postDate)
                .set(Transaction::getHasClear, hasClear)
                .eq(Transaction::getChannelTranId, channelTranId)
                .update();
    }

    @Override
    public Boolean updateRefundTran(String channelTranId, String status, BigDecimal settleAmount, String settleCurrency, Date settleDate, Date postDate, Boolean hasClear) {
        return updateChain()
                .set(Transaction::getStatus, status)
                .set(Transaction::getSettleAmount, settleAmount)
                .set(Transaction::getSettleCurrency, settleCurrency)
                .set(Transaction::getBillingAmount, settleAmount)
                .set(Transaction::getBillingCurrency, settleCurrency)
                .set(Transaction::getSettleDate, settleDate)
                .set(Transaction::getPostDate, postDate)
                .set(Transaction::getHasClear, hasClear)
                .eq(Transaction::getChannelTranId, channelTranId)
                .update();
    }

    @Override
    public Boolean updateTranSettleData(
            String channelTranId,
            String channelSettleId,
            String settleTranId,
            String status,
            BigDecimal settleAmount,
            String settleCurrency,
            Date settleDate,
            Date postDate,
            Boolean hasClear) {
        return updateChain()
                .set(Transaction::getStatus, status)
                .set(Transaction::getSettleAmount, settleAmount)
                .set(Transaction::getSettleCurrency, settleCurrency)
                .set(Transaction::getSettleDate, settleDate)
                .set(Transaction::getPostDate, postDate)
                .set(Transaction::getHasClear, hasClear)
                .set(Transaction::getChannelSettleTranId, channelSettleId)
                .set(Transaction::getSettleTranId, settleTranId)
                .eq(Transaction::getChannelTranId, channelTranId)
                .update();
    }

    @Override
    public Page<Transaction> paging(Long userId, Role role, Page<Transaction> pageable, Long targetUserId, String status, String type, String cardNumber, String startDate, String endDate, Long userCardId) {
        QueryChain<Transaction> queryChain = queryChain();
        if (RegexUtil.checkStringIsNotNull(cardNumber)) {
            UserCard userCard = userCardService.getByCardNumber(cardNumber);
            queryChain.eq(Transaction::getCardNumber, (userCard.getCardNumber()));
        }
        if (role.getHasAllData()) {
            queryChain.leftJoin(USER).on(TRANSACTION.USER_ID.eq(USER.ID)).where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
            if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
                queryChain.eq(Transaction::getUserId, targetUserId);
            }
        } else {
            queryChain.eq(Transaction::getUserId, userId);
        }
        if (RegexUtil.checkStringIsNotNull(status)) {
            queryChain.eq(Transaction::getStatus, status);
        }
        if (userCardId != null) {
            queryChain.eq(Transaction::getUserCardId, userCardId);
        }
        if (RegexUtil.checkStringIsNotNull(type)) {
            queryChain.eq(Transaction::getTransactionType, type);
        }
        if (RegexUtil.checkObjectIsNotNull(startDate)) {
            queryChain.ge(Transaction::getTranDate, DateUtil.getDayBeginDate(startDate, "yyyy-MM-dd"));
        }
        if (RegexUtil.checkObjectIsNotNull(endDate)) {
            queryChain.le(Transaction::getTranDate, DateUtil.getDayEndDate(endDate, "yyyy-MM-dd"));
        }
        queryChain.orderBy(Transaction::getTranDate, false);
        return queryChain.page(pageable);
    }

    @Override
    public Page<Transaction> paging(
            Long userId,
            Page<Transaction> pageable,
            Long targetUserId,
            String status,
            String type,
            String cardNumber,
            String startDate,
            String endDate,
            Long userCardId,
            Long cardTypeId,
            String channelCode) {
        QueryChain<Transaction> queryChain = queryChain();
        queryChain.leftJoin(USER).on(USER.ID.eq(TRANSACTION.USER_ID));
        queryChain.leftJoin(BOSS_USER.as("dealer")).on(USER.BE_LONG_TO_DEALER.eq(BOSS_USER.ID));
        queryChain.select(TRANSACTION.ALL_COLUMNS);
        queryChain.select(BOSS_USER.EMAIL.as("dealerAccount"));
        queryChain.select(USER.ACCOUNT.as("account"));
        Long bossUserId = BossUserUtil.getIdNotNull();
        if (!BossUserUtil.hasAllData()) {
            queryChain.and(
                    BOSS_USER.as("dealer").ID.eq(bossUserId)
                            .or(BOSS_USER.as("dealer").PARENT_ID.eq(bossUserId)));
        }
        if (RegexUtil.checkStringIsNotNull(cardNumber)) {
            UserCard userCard = userCardService.getByCardNumber(cardNumber);
            queryChain.eq(Transaction::getCardNumber, (userCard.getCardNumber()));
        }
        if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
            queryChain.eq(Transaction::getUserId, targetUserId);
        }

        if (RegexUtil.checkStringIsNotNull(status)) {
            queryChain.eq(Transaction::getStatus, status);
        }
        if (RegexUtil.checkStringIsNotNull(type)) {
            queryChain.eq(Transaction::getTransactionType, type);
        }
        if (userCardId != null) {
            queryChain.eq(Transaction::getUserCardId, userCardId);
        }
        if (cardTypeId != null && cardTypeId > 0){
            queryChain.eq(Transaction::getCardTypeId, cardTypeId);
        }
        if (RegexUtil.checkStringIsNotNull(channelCode)){
            queryChain.eq(Transaction::getChannel, channelCode);
        }
        if (RegexUtil.checkObjectIsNotNull(startDate)) {
            queryChain.ge(Transaction::getTranDate, DateUtil.getDayBeginDate(startDate, "yyyy-MM-dd"));
        }
        if (RegexUtil.checkObjectIsNotNull(endDate)) {
            queryChain.le(Transaction::getTranDate, DateUtil.getDayEndDate(endDate, "yyyy-MM-dd"));
        }
        queryChain.orderBy(Transaction::getTranDate, false);
        return queryChain.page(pageable);
    }

    @Override
    public List<UserTransactionVo> sumCount(Long userId, Role role, Date startDate, Date endDate) {
        // 计算时间范围
        QueryWrapper query = QueryWrapper.create()
                .select(
                        "DATE_FORMAT(vcc_transaction.tran_date, '%Y-%m-%d') as date",
                        "COUNT(vcc_transaction.id) as sumCount",
                        "COALESCE(SUM(vcc_transaction.billing_amount), 0) as sumAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN 1 ELSE 0 END ) AS successAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS successAuthAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH')  THEN 1 ELSE 0 END ) AS failedAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS failedAuthAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as authAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as refundAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN billing_amount ELSE 0 END), 0) as reversalAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(startDate, endDate)
                .groupBy("DATE_FORMAT(tran_date, '%Y-%m-%d')")
                .orderBy("date", true); // 按日期降序
        if (role.getHasAllData()) {
            query.leftJoin(USER).on(TRANSACTION.USER_ID.eq(USER.ID)).where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
        } else {
            query.eq(Transaction::getUserId, userId);
        }
        return mapper.selectListByQueryAs(query, UserTransactionVo.class);
    }

    @Override
    public List<UserTransactionVo> sumCount(Long userId, Date startDate, Date endDate) {
        QueryWrapper query = QueryWrapper.create()
                .select(
                        "DATE_FORMAT(vcc_transaction.tran_date, '%Y-%m-%d') as date",
                        "COUNT(vcc_transaction.id) as sumCount",
                        "COALESCE(SUM(vcc_transaction.billing_amount), 0) as sumAmount",
                        "SUM(CASE WHEN vcc_transaction.status = 'SUCCESS' THEN 1 ELSE 0 END) as successCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.status = 'SUCCESS' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as successAmount",
                        "SUM(CASE WHEN vcc_transaction.status = 'FAILED' THEN 1 ELSE 0 END) as failedCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.status = 'FAILED' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as failedAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as authAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as refundAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN billing_amount ELSE 0 END), 0) as reversalAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(
                        DateUtil.getDayBeginDate(startDate),
                        DateUtil.getDayEndDate(endDate)
                )
                .groupBy("DATE_FORMAT(tran_date, '%Y-%m-%d')")
                .orderBy("date", true); // 按日期降序
        query.eq(Transaction::getUserId, userId);
        return mapper.selectListByQueryAs(query, UserTransactionVo.class);
    }


    @Override
    public List<JSONObject> statistics() {
        // 计算时间范围
        QueryChain<Transaction> queryChain = queryChain()
                .select(
                        "user_id as userId",
                        "COUNT(vcc_transaction.id) as sumCount",
                        "COALESCE(SUM(vcc_transaction.billing_amount), 0) as sumAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN 1 ELSE 0 END ) AS successAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS successAuthAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH')  THEN 1 ELSE 0 END ) AS failedAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS failedAuthAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as authAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as refundAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN billing_amount ELSE 0 END), 0) as reversalAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(
                        DateUtil.getDayBeginDate(DateTime.now().offset(DateField.DAY_OF_MONTH, -1)),
                        DateUtil.getDayEndDate(DateTime.now().offset(DateField.DAY_OF_MONTH, -1)))
                .groupBy(Transaction::getUserId);// 按日期降序
        return mapper.selectListByQueryAs(queryChain, Row.class).stream().map(JSONObject::new).toList();
    }

    @Override
    public List<JSONObject> statistics(DateTime startDate, DateTime endDate) {
        // 计算时间范围
        QueryChain<Transaction> queryChain = queryChain()
                .select(
                        "user_id as userId",
                        "COUNT(vcc_transaction.id) as sumCount",
                        "COALESCE(SUM(vcc_transaction.billing_amount), 0) as sumAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN 1 ELSE 0 END ) AS successAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS successAuthAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH')  THEN 1 ELSE 0 END ) AS failedAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS failedAuthAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as authAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as refundAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN billing_amount ELSE 0 END), 0) as reversalAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(startDate, endDate)
                .groupBy(Transaction::getUserId);// 按日期降序
        return mapper.selectListByQueryAs(queryChain, Row.class).stream().map(JSONObject::new).toList();
    }

    @Override
    public List<JSONObject> statistics(DateTime startDate, DateTime endDate, Long userId, Long dealerId) {
        QueryWrapper query = QueryWrapper.create()
                .select(
                        "DATE_FORMAT(vcc_transaction.tran_date, '%Y-%m-%d') as date",
                        "COUNT(vcc_transaction.id) as sumCount",
                        "COALESCE(SUM(vcc_transaction.billing_amount), 0) as sumAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN 1 ELSE 0 END ) AS successAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS successAuthAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH')  THEN 1 ELSE 0 END ) AS failedAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS failedAuthAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as authAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as refundAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN billing_amount ELSE 0 END), 0) as reversalAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(
                        startDate,
                        endDate
                )
                .groupBy("DATE_FORMAT(vcc_transaction.tran_date, '%Y-%m-%d')");
        if (userId != null) {
            query.and(Transaction::getUserId).eq(userId);
        }
        if (dealerId != null) {
            query.leftJoin(USER).on(TRANSACTION.USER_ID.eq(USER.ID));
            query.leftJoin(BOSS_USER).on(USER.BE_LONG_TO_DEALER.eq(BOSS_USER.ID));
            query.and(BOSS_USER.ID.eq(dealerId).or(BOSS_USER.PARENT_ID.eq(dealerId)));
        }
        return mapper.selectListByQueryAs(query, Row.class).stream().map(JSONObject::new).toList();
    }

    @Override
    public List<CountData> successCountById(Long userId) {
        List<CountData> countData = mapper.successCountById(userId);
        for (int i = 1; i <= 30; i++) {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, -i);
            String date = DateUtil.format("yyyy-MM-dd", calendar.getTime());
            CountData tempData = countData.stream().filter(it -> it.getDate().equals(date)).findFirst().orElse(null);
            if (tempData == null) {
                countData.add(new CountData(date, 0L));
            }
        }
        return countData.stream().sorted(Comparator.comparing(it -> DateUtil.parse(it.getDate(), "yyyy-MM-dd"))).collect(Collectors.toList());
    }

    @Override
    public List<AmountData> successAmountByUserId(Long userId) {
        List<AmountData> amountData = mapper.successAmountById(userId);
        for (int i = 1; i <= 30; i++) {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, -i);
            String date = DateUtil.format("yyyy-MM-dd", calendar.getTime());
            AmountData tempData = amountData.stream().filter(it -> it.getDate().equals(date)).findFirst().orElse(null);
            if (tempData == null) {
                amountData.add(new AmountData(date, BigDecimal.valueOf(0)));
            }
        }
        return amountData.stream().sorted(Comparator.comparing(it -> DateUtil.parse(it.getDate(), "yyyy-MM-dd"))).collect(Collectors.toList());

    }

    @Override
    public List<RateData> successRateByUserId(Long userId) {
        List<CountData> sumCountData = mapper.countById(userId);
        List<CountData> successCountData = mapper.successCountById(userId);
        ArrayList<RateData> rateDatas = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            Calendar calendar = Calendar.getInstance();
            RateData rateData = new RateData();
            calendar.add(Calendar.DAY_OF_MONTH, -i);
            String date = DateUtil.format("yyyy-MM-dd", calendar.getTime());
            rateData.setDate(date);
            CountData tempSuccessCount = successCountData.stream().filter(it -> it.getDate().equals(date)).findFirst().orElse(null);
            CountData tempSumCount = sumCountData.stream().filter(it -> it.getDate().equals(date)).findFirst().orElse(new CountData());
            BigDecimal rate = BigDecimal.valueOf(0);
            //如果成功的空则成功率为0
            if (tempSuccessCount != null) {
                //如果成功不为0，总的肯定不会为空
                rate = new BigDecimal(tempSuccessCount.getCount()).divide(new BigDecimal(tempSumCount.getCount()), 2, RoundingMode.UP);
            }
            rateData.setRate(rate);
            rateDatas.add(rateData);
        }
        return rateDatas.stream().sorted(Comparator.comparing(it -> DateUtil.parse(it.getDate(), "yyyy-MM-dd"))).collect(Collectors.toList());
//        return rateDatas;
    }


    @Override
    public List<JSONObject> cardTypeStatistics(DateTime startDate, DateTime endDate, List<Long> cardTypeIds) {
        QueryWrapper query = QueryWrapper.create()
                .select(
                        "vcc_transaction.card_type_id as cardTypeId",
                        "COUNT(vcc_transaction.id) as sumCount",
                        "COALESCE(SUM(vcc_transaction.billing_amount), 0) as sumAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN 1 ELSE 0 END ) AS successAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS successAuthAmount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH')  THEN 1 ELSE 0 END ) AS failedAuthCount",
                        "COALESCE ( SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH') THEN vcc_transaction.billing_amount ELSE 0 END ), 0 ) AS failedAuthAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as authAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN vcc_transaction.billing_amount ELSE 0 END), 0) as refundAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "COALESCE(SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN billing_amount ELSE 0 END), 0) as reversalAmount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(
                        cn.hutool.core.date.DateUtil.beginOfDay(startDate),
                        cn.hutool.core.date.DateUtil.endOfDay(endDate)
                )
                .groupBy(Transaction::getCardTypeId);// 按日期降序
        if (cardTypeIds != null && !cardTypeIds.isEmpty()) {
            query.and(TRANSACTION.CARD_TYPE_ID.in(cardTypeIds));
        }
        return mapper.selectListByQueryAs(query, Row.class).stream().map(JSONObject::new).toList();
    }

    @Override
    public JSONObject userCardStatistics(DateTime startDate, DateTime endDate, Long userCardId) {
        QueryChain<Transaction> queryChain = queryChain()
                .select(
                        "COUNT(vcc_transaction.id) as sumCount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'SUCCESS' and vcc_transaction.transaction_type = 'AUTH') THEN 1 ELSE 0 END ) AS successAuthCount",
                        "SUM( CASE WHEN (vcc_transaction.STATUS = 'FAILED'  and vcc_transaction.transaction_type = 'AUTH')  THEN 1 ELSE 0 END ) AS failedAuthCount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'AUTH' THEN 1 ELSE 0 END) as authCount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REFUND' THEN 1 ELSE 0 END) as refundCount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'REVERSAL' THEN 1 ELSE 0 END) as reversalCount",
                        "SUM(CASE WHEN vcc_transaction.transaction_type = 'VERIFY' THEN 1 ELSE 0 END) as verifyCount"
                )
                .from(Transaction.class)
                .and(Transaction::getTranDate).between(
                        cn.hutool.core.date.DateUtil.beginOfDay(startDate),
                        cn.hutool.core.date.DateUtil.endOfDay(endDate)
                );// 按日期降序
        queryChain.and(TRANSACTION.USER_CARD_ID.eq(userCardId));
        return JsonUtil.jsonStringToObject(queryChain.oneAs(Row.class), JSONObject.class);
    }

    @Override
    public List<Long> listUserCardIdByDate(DateTime startDate, DateTime endDate) {
        return queryChain()
                .select(TRANSACTION.USER_CARD_ID)
                .and(TRANSACTION.TRAN_DATE.between(startDate, endDate))
                .listAs(Long.class)
                .stream()
                .distinct()
                .filter(Objects::nonNull)
                .toList();
    }
}
